import BaseVue from '@/lib/base/BaseVue';
import Component from 'vue-class-component';
import styles from './SliderMore.module.less';
import { Prop } from 'vue-property-decorator';

let lastSliderMore: ISliderMore | null;

@Component
export default class ISliderMore extends BaseVue {
    // 第一次触摸坐标
    private startX = 0;
    private startY = 0;
    // 滑动距离
    private translateDistance = 0;
    // 最大滑动距离
    private maxTranslateDistance = 0;
    // 多点触摸时，最后手指抬起时的滑动距离
    private lastEndTranslateDistance = 0;
    // 是否打开状态
    private isOpen = false;
    // 开始触摸时间戳
    private startTime = 0;
    // 触摸结束
    private touched = true;
    // 手指编号
    private identifier = -1;
    /**
     * 滑动距离超过 右侧隐藏操作区域宽度百分之几时  触发 打开/关闭
     */
    @Prop({
        default: 50
    })
    private sliderProgress!: number;

    // 轻扫宽度达到多少 触发 打开/关闭
    @Prop({
        default: 40
    })
    private swipeWidth!: number;
    // 轻扫时间小于多少 触发 打开/关闭
    @Prop({
        default: 200
    })
    private swipeTime!: number;


    /**
     * 滑动样式
     */
    private get styles() {
        return {
            webkitTransform: `translateX(${this.translateDistance}px)`,
            transform: `translateX(${this.translateDistance}px)`,
        }
    }

    public render() {
        return (
            <div
                class={styles.app}>
                <div ref="body" class={styles.body} style={this.styles}>
                    {this.$slots.default}
                    <div class={styles.slider} ref="slider">
                        {this.$slots.slider}
                    </div>
                </div>
            </div>
        )
    }

    public created() {
        this.init();
    }
    
    public beforeDestroy() {
        if (lastSliderMore && lastSliderMore === this) {
            lastSliderMore.unBindEvent();
            lastSliderMore.reset();
        }
    }

    public handleEvent(e: TouchEvent) {
        const touch = e.changedTouches[0];
        switch (e.type) {
            case 'touchstart': {

                // 最后滑动的不是自己，则关闭最后滑动的
                if (lastSliderMore && lastSliderMore !== this) {
                    lastSliderMore.unBindEvent();
                    lastSliderMore.reset();
                }
                // 设置手指编号
                if (this.identifier === -1) {
                    this.identifier = touch.identifier;
                } else {
                    return;
                }
                this.bindEvent();
                const element = this.$refs.body as HTMLDivElement;
                element.style.transition = 'none';
                element.style.webkitTransition = 'none';
                this.startX = touch.clientX;
                this.startY = touch.clientY;
                this.startTime = Date.now();
                lastSliderMore = this;
                break;
            }
            case 'touchmove':
                if (this.identifier !== touch.identifier) {
                    e.stopImmediatePropagation();
                    e.preventDefault();
                    return;
                }
                const moveX = touch.clientX;
                const moveY = touch.clientY;
                const distance = this.getDistance(moveX);
                // 当滑动方向不是左右时，重新计算滑动距离和初始坐标
                if (!this.isSlider(moveX, moveY)) {
                    this.startX = moveX;
                    this.startY = moveY;
                    if (this.isTouch()) {
                        e.stopImmediatePropagation();
                        e.preventDefault();
                    }
                    return;
                }
                e.preventDefault();
                e.stopImmediatePropagation();
                this.translateDistance = distance;
                break;
            case 'touchend':
            case 'touchcancel': {
                if (this.identifier !== touch.identifier) {
                    e.stopImmediatePropagation();
                    return;
                }
                this.unBindEvent();
                this.next();
                break;
            }

        }
    }


    /**
     * 重置
     */
    public reset() {
        this.translateDistance = 0;
        this.lastEndTranslateDistance = 0;
        this.next();
    }


    private init() {
        this.$nextTick(() => {
            const app = this.$el as HTMLElement;
            const slider = this.$refs.slider as HTMLElement;
            this.maxTranslateDistance = -slider.offsetWidth;
            app.addEventListener('touchstart', this, false);
        });
    }

    /**
     * 绑定事件
     */
    private bindEvent() {
        const app = this.$el as HTMLElement;
        app.addEventListener('touchmove', this, {
            passive: false
        });
        app.addEventListener('touchend', this, false);
        app.addEventListener('touchcancel', this, false);
    }
    /**
     * 解绑事件
     */
    private unBindEvent() {
        const app = this.$el as HTMLElement;
        app.removeEventListener('touchmove', this, false);
        app.removeEventListener('touchend', this, false);
        app.removeEventListener('touchcancel', this, false);
    }

    /**
   *  抬起后执行
   */
    private next() {
        this.startY = 0;
        this.startX = 0;
        // 滑动时间小于 N ms
        const speedOk = Date.now() - this.startTime <= this.swipeTime;
        // 滑动距离大于 N  px
        const distanceOk = this.translateDistance <= -this.swipeWidth;
        this.touched = true;

        const element = this.$refs.body as HTMLDivElement;
        element.style.transition = 'transform .3s';
        element.style.webkitTransition = 'transform .3s';
        this.identifier = -1;
        // 快速轻扫
        if (speedOk && distanceOk) {
            if (!this.isOpen) {
                this.open();
                return;
            } else if (this.maxTranslateDistance - this.translateDistance <= -this.swipeWidth) {
                this.close();
                return;
            }
        }

        // 正常速度
        if (this.translateDistance <= this.maxTranslateDistance * this.sliderProgress / 100) {
            this.open();
        } else {
            this.close();
        }

    }
    /**
     * 打开
     */
    private open() {
        this.translateDistance = this.maxTranslateDistance;
        this.lastEndTranslateDistance = this.translateDistance;
        this.isOpen = true;
    }
    /**
     * 关闭
     */
    private close() {
        this.lastEndTranslateDistance = 0;
        this.translateDistance = 0;
        this.isOpen = false;
        lastSliderMore = null;
    }

    /**
     * 是否左右滑动
     * @param moveX 
     * @param moveY 
     */
    private isSlider(moveX: number, moveY: number) {
        if (this.isTouch()) {
            return true;
        }
        const angle = this.getAngle(moveX, moveY);
        return angle >= 135 || angle <= -135 || (angle >= -45 && angle <= 45)
    }

    private isTouch() {
        // 如果触发过滑动状态 ，则需要等手指抬起
        if (!this.touched) {
            return true;
        }
        const slider = this.translateDistance !== 0 && this.translateDistance != this.maxTranslateDistance;
        // 触发过滑动状态 
        if (slider) {
            this.touched = false;
        }
        return slider;
    }


    /**
     * 获取手指滑动角度
     * @param moveX  
     * @param moveY 
     */
    private getAngle(moveX: number, moveY: number) {
        return Math.atan2(moveY - this.startY, moveX - this.startX) * 180 / Math.PI;
    }

    /**
     * 获取滑动距离
     * @param moveX
     */
    private getDistance(moveX: number) {
        let d = (moveX - this.startX) * 0.6 + this.lastEndTranslateDistance;
        // 滑动距离超过最大滑动距离
        if (d <= this.maxTranslateDistance) {
            d = this.maxTranslateDistance;
        } else if (d >= 0) { // 滑动距离小于等于0
            d = 0;
        }
        return d;
    }
}
